<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<title>接口-实现接口的三种方式</title>
</head>
<body>
<script type="text/javascript">
	
	//接口的实现方式有三种

	// 1 注解描述的方式

	/**
	 *	interface Composite () {
	 *		function add(obj);
	 *		function remove(obj);
	 *		function update(obj);
	 *	}
	 */
	/*
	// CompositeImpl implements Composite
	var CompositeImpl = function () {}

	CompositeImpl.prototype = {
		add: function (obj) {
			// do something...
		},
		remove: function (obj) {
			// do something...
		},
		update: function (obj) {
			// do something...
		}
	}

	Object.defineProperty(CompositeImpl.prototype, 'constructor', {
		enumerable: false, //设置能否被枚举
		value: CompositeImpl
	})

	var c = new CompositeImpl();
	*/

	// 2 属性检测的方式

	/**
	 *	interface Composite () {
	 *		function add(obj);
	 *		function remove(obj);
	 *		function update(obj);
	 *	}
	 *
	 *	interface formItem () {
	 *		function select(obj);
	 *	}
	 */
	/*
	// CompositeImpl implements Composite, formItem
	var CompositeImpl = function () {
		// 显示的在类的内部 接受所有实现的接口
		// 规范： 在类的内部定义一个数组（名字要固定）
		this.implementsInterfaces = ['Composite', 'formItem'];
	}

	CompositeImpl.prototype = {
		add: function (obj) {
			//do something...
			alert('add...');
		},
		remove: function (obj) {
			//do something...
			alert('remove...');
		},
		update: function (obj) {
			//do something...
			alert('update...');
		},
		select: function (obj) {
			//do something...
			alert('select...');
		},
	}

	Object.defineProperty(CompositeImpl.prototype, 'constructor', {
		enumerable: false, //设置能否被枚举
		value: CompositeImpl
	})

	//检测CompositeImpl类的对象
	function checkCompositeImpl (interface) {
		// 判断当前对象属否实现所有接口
		if(!isImplements(interface, 'Composite', 'formItem')){
			// 判断
			throw new Error('Object does not implement a required instance!');
		}
	}

	// 公共的具体的检测方法(核心方法)
	function isImplements (obj) {
		// arguments对象 获得函数的实际参数
		for(var i = 1; i < arguments.length; i++){
			var interfaceName = arguments[i];
			var interfaceFound = false;
			for(var j = 0; j < obj.implementsInterfaces.length; j++){
				if(obj.implementsInterfaces[j] == interfaceName){
					interfaceFound = true;
					break;
				}
			}
			if(!interfaceFound){
				return false;
			}
		}
		return true;
	}

	// 检测
	var c1 = new CompositeImpl();
	checkCompositeImpl(c1);
	c1.add();
	*/

	// 3 鸭式辩型的方式

	//接口类，用来创建接口
	// 参数1: 接口名称
	// 参数2: 方法名（数组）
	var Interface = function (name, methods) {
		if(arguments.length != 2){
			throw new Error('Interface constructor called with "+arguments.length+"arguments,but expected exactly 2');
		}
		this.name = name;
		this.mothods = [];
		for(var i = 0; i < methods.length; i++){
			if(typeof methods[i] !== 'string'){
				throw new Error('Interface constructor expects mothed names to be'+'passes in as a string');
			}
			this.mothods.push(methods[i]);
		}
	}

	Interface.ensureImplements = function (object) {
		if(arguments.length < 2){
			throw new Error('Interface constructor called with "+arguments.length+"arguments,but expected exactly 2');
		}
		for(var i = 1; i < arguments.length; i++){
			var instanceInterface = arguments[i];
			if(instanceInterface.constructor !== Interface){
				throw new Error('the arguments constructor not be Interface Class');
			}
			for(var j = 0; j < instanceInterface.mothods.length; j++){
				var mothedName = instanceInterface.mothods[j];
				if(!object[mothedName] || typeof object[mothedName] !== 'function'){
					throw new Error('the mothed name ' + mothedName + ' is not found');
				}
			}
		}
	}	

	//创建接口
	var CompositeInterface = new Interface('CompositeInterface',['add','remove']);
	var FormItemInterface = new Interface('FormItemInterface',['update','select']);

	// CompositeImpl implements Composite, formItem
	var CompositeImpl = function () {}

	CompositeImpl.prototype = {
		add: function (obj) {
			//do something...
			alert('add...');
		},
		remove: function (obj) {
			//do something...
			alert('remove...');
		},
		update: function (obj) {
			//do something...
			alert('update...');
		},
		select: function (obj) {
			//do something...
			alert('select...');
		},
	}

	Object.defineProperty(CompositeImpl.prototype, 'constructor', {
		enumerable: false, //设置能否被枚举
		value: CompositeImpl
	})

	var c2 = new CompositeImpl();
	c2.add();

	Interface.ensureImplements(c2, CompositeInterface, FormItemInterface);	

</script>
</body>
</html>